import WatchGradualNumber from "@/utils/WatchGradualNumber";
import Mota, { MotaInterface } from "@/mota";
import { ImageState } from "@/mota/data/MapDataUtils";
import { ImageName } from "@/mota/data/ImageLoader";
import AttributeUtils from "@/mota/utils/HeroUtils/AttributeUtils";
import PackUtils from "@/mota/utils/HeroUtils/PackUtils/index";
import Blockutils from "@/utils/BlockUtils";
import { getItemMap, useItemMap } from "@/mota/data/ItemDataUnit";

export type HeroState = "control" | "stop";

type HeroImageType = "英雄上" | "英雄下" | "英雄左" | "英雄右";

type HeroImage = HeroImageType extends ImageName ? HeroImageType : never;

export default class HeroUtils implements MotaInterface {

	public Mota!: Mota;

	public X!: WatchGradualNumber;

	public Y!: WatchGradualNumber;

	public Image: HeroImage = "英雄下";

	public ImageState: ImageState = "first";

	public heroState: HeroState = "control";

	public Attribute: AttributeUtils;

	public pack: PackUtils;

	public ZIndex: number = 3;

	public Children: MotaInterface["Children"];

	public block: Blockutils = new Blockutils();

	constructor(mota: Mota) {
		this.Mota = mota;
		const { speedUtils } = mota;
		this.X = speedUtils.MakeChanger(0);
		this.Y = speedUtils.MakeChanger(0);

		this.Attribute = new AttributeUtils(this);
		this.pack = new PackUtils(this);

		this.Children = [
			this.Attribute,
			this.pack,
		];
	}

	/**
	 * 获取物品
	 * @param name 获取物品的名称(图片ID)
	 */
	public GetItem(name: ImageName): boolean {
		const { pack, Attribute, Mota: { tip } } = this;
		const infoList = getItemMap[name];
		if (infoList !== undefined) {
			tip.AddIconMessage(name, `获得${name}，得到${Attribute.AddAttribute(infoList)}`);
			return true;
		}

		const consumablesInfo = pack.AppendConsumablesResult(name);
		if (consumablesInfo !== undefined) {
			tip.AddIconMessage(name, `获得${consumablesInfo}`);
			return true;
		}

		const propsInfo = pack.AppendPropResult(name);
		if (propsInfo !== undefined) {
			tip.AddIconMessage(name, `获得${propsInfo}`);
			return true;
		}

		tip.AddIconMessage(name, "非可获取物品");
		return false;
	}

	/**
	 * 使用物品
	 * @param target 物品使用的目标对象
	 */
	public UseItemTo(target: ImageName): boolean {
		const { Attribute, Mota: { tip } } = this;
		const infoList = useItemMap[target];
		if (infoList !== undefined) {
			const reduceRes = Attribute.ReduceAttribute(infoList);
			if (reduceRes !== undefined) {
				tip.AddIconMessage(target, `缺少${reduceRes}`);
				return false;
			}
		}
		else {
			tip.AddIconMessage(target, "非可使用消耗品");
			return false;
		}
		return true;
	}

	public async DoingSome(doing: () => Promise<void>): Promise<void> {
		this.block.Wait(async () => {
			this.heroState = "stop";
			await doing();
			this.block.Release();
		}, () => {
			this.heroState = "control";
		});
	}

	public GetFacePoint(): [number, number] | undefined {
		const { Image, X, Y } = this;
		let x = X.Target;
		let y = Y.Target;
		if (Image === "英雄上") { y -= 1; if (y < 0) { return undefined; } }
		else if (Image === "英雄下") { y += 1; if (y >= 11) { return undefined; } }
		else if (Image === "英雄左") { x -= 1; if (x < 0) { return undefined; } }
		else if (Image === "英雄右") { x += 1; if (x >= 11) { return undefined; } }
		return [x, y];
	}

	public JudgeKey: MotaInterface["JudgeKey"] = (keyUtils): void => {
		const { heroState, Image, pack, Mota: { onBuild } } = this;
		if (onBuild) { return; }
		if (heroState !== "control") { return; }

		for (const key of keyUtils.keyHistory) {
			if (key === "ArrowUp") {
				this.MoveHeroUp();
				break;
			}
			else if (key === "ArrowDown") {
				this.MoveHeroDown();
				break;
			}
			else if (key === "ArrowLeft") {
				this.MoveHeroLeft();
				break;
			}
			else if (key === "ArrowRight") {
				this.MoveHeroRight();
				break;
			}
			else if (key === "c") {
				if (Image === "英雄上") {
					this.Image = "英雄右";
				}
				else if (Image === "英雄右") {
					this.Image = "英雄下";
				}
				else if (Image === "英雄下") {
					this.Image = "英雄左";
				}
				else if (Image === "英雄左") {
					this.Image = "英雄上";
				}
				keyUtils.delete(key);
			}
			else if (key === "t") {
				this.GetFacePoint();
				keyUtils.delete(key);
			}
			else if (key === "b") {
				this.DoingSome(async () => {
					await pack.Open();
				});
				keyUtils.delete(key);
			}
			const utils = pack.GetUtilsByKeyboard(key);
			if (utils !== undefined) {
				this.DoingSome(async () => {
					await pack.UseItem(utils);
				});
				keyUtils.delete(key);
			}
		}
	}

	public async MoveHeroUp(): Promise<void> {
		await this.MoveHero("英雄上", 0, -1);
	}

	public async MoveHeroDown(): Promise<void> {
		await this.MoveHero("英雄下", 0, 1);
	}

	public async MoveHeroLeft(): Promise<void> {
		await this.MoveHero("英雄左", -1, 0);
	}

	public async MoveHeroRight(): Promise<void> {
		await this.MoveHero("英雄右", 1, 0);
	}

	public async MoveHero(image: HeroImage, x: number, y: number) {
		const { Mota, X, Y } = this;
		if (X.HasNext || Y.HasNext) {
			return;
		}
		this.Image = image;
		const tx = X.Value + x;
		const ty = Y.Value + y;
		if (tx < 0 || tx > 10 || ty < 0 || ty > 10) {
			return;
		}
		this.DoingSome(async () => {
			if (await Mota.JudgeHeroMove(tx, ty)) {
				X.Value = tx;
				Y.Value = ty;
				this.ImageState = "run";
			}
		});
	}

	public Draw: MotaInterface["Draw"] = (draw) => {
		const { _2d } = draw;
		const { Mota: { onBuild } } = this;
		if (onBuild) { return; }

		const { Image, X, Y, ImageState } = this.Mota.hero;

		_2d.save();

		draw.translate(4, 0);

		draw.DrawUnti([Image, true, [X.Value, Y.Value], ImageState]);

		_2d.restore();
	}

	public Trigger(): void {
		const { X, Y } = this;
		if (X.HasNext || Y.HasNext) {
			X.Trigger();
			Y.Trigger();
			if (!X.HasNext && !Y.HasNext) {
				this.ImageState = "first";
			}
		}
	}
}
